
#import "UDPClient.h"
#import "Event.h"
#import <math.h>

@implementation UDPClient

@synthesize echo = _echo;
@synthesize delegate = _delegate;

- (id)initWithDelegate:(id<InputEventDelegate>)delegate
{
    self = [super init];
    if (self)
    {
        self.delegate = delegate;
    }
    
    return self;
}

- (BOOL)runServerOnPort:(NSUInteger)port
// One of two Objective-C 'mains' for this program.  This creates a UDP 
// object and runs it in server mode.
{
    assert(self.echo == nil);
    
    self.echo = [[UDP alloc] init];
    assert(self.echo != nil);
    
    self.echo.delegate = self;
    
    [self.echo startServerOnPort:port];
    
    while (self.echo != nil) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
    
    // The loop above is supposed to run forever.  If it doesn't, something must 
    // have failed and we want main to return EXIT_FAILURE.
    
    return NO;
}

- (BOOL)runClientWithHost:(NSString *)host port:(NSUInteger)port
// One of two Objective-C 'mains' for this program.  This creates a UDP 
// object in client mode, talking to the specified host and port, and then 
// periodically sends packets via that object.
{
    assert(host != nil);
    assert( (port > 0) && (port < 65536) );
    
    assert(self.echo == nil);
    
    self.echo = [[UDP alloc] init];
    assert(self.echo != nil);
    
    self.echo.delegate = self;
    
    [self.echo startConnectedToHostName:host port:port];
    
    while (self.echo != nil)
    {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
    
    // The loop above is supposed to run forever.  If it doesn't, something must 
    // have failed and we want main to return EXIT_FAILURE.
    
    return YES;
}

-(void) send:(const UInt8 *)data :(int)dataLength
{
    [self.echo sendData:[NSData dataWithBytes:data length:dataLength]];
}

- (void)sendPacket
// Called by the client code to send a UDP packet.  This is called immediately 
// after the client has 'connected', and periodically after that from the send 
// timer.
{
    NSData *    data;
    
    assert(self.echo != nil);
    assert( ! self.echo.isServer );
    
    data = [[NSString stringWithFormat:@"%zu bottles of beer on the wall", 99] dataUsingEncoding:NSUTF8StringEncoding];
    assert(data != nil);
    
    [self.echo sendData:data];
    
    /*self.sendCount += 1;
     if (self.sendCount > 99) {
     self.sendCount = 0;
     }*/
}

- (void)echo:(UDP *)echo didReceiveData:(NSData *)data fromAddress:(NSData *)addr
// This UDP delegate method is called after successfully receiving data.
{
    assert(echo == self.echo);
#pragma unused(echo)
    assert(data != nil);
    assert(addr != nil);
    
    [self.delegate receivedData: data];

    //NSLog(@"x: %d, y: %d", x, y);

/*    NSMutableString *bytesString = [NSMutableString stringWithCapacity:24];
    
    for(int i = 0; i < sizeof(SInt64); i++)
    {
        UInt8 byte = bytes[i];
        [bytesString appendFormat:@"%u ", byte];
    }
    
    for(int i = 0; i < sizeof(SInt16); i++)
    {
        UInt8 byte = timeStampBytes[i];
        [bytesString appendFormat:@"%u ", byte];
        x += byte << (i * 8);
        //NSLog(@"byte: %u", timeStampBytes[i]);
    }
    
    for(int i = 2; i < sizeof(SInt16) + 2; i++)
    {
        UInt8 byte = timeStampBytes[i];
        [bytesString appendFormat:@"%u ", byte];
        y += byte << (i * 8);
        //NSLog(@"byte: %u", timeStampBytes[i]);
    }
    
    NSLog(@"Data received from master: %@: %d", bytesString, time);
 */
    //NSLog(@"bytes: %@", bytesString);
//    NSValue *val = [NSValue valueWithBytes:timeBuffer objCType:@encode(NSUInteger) ];
//    NSNumber 
//    NSNumber *timeStamp = [[NSNumber alloc] initWithBytes:timeBuffer objCType:@encode(NSUInteger)];

    //   NSNumber *x = [[NSNumber alloc]initWithBytes:buffer objCType:@encode(NSInteger)];
//    //NSLog(@"received %@ from %@", timeStamp, DisplayAddressForAddress(addr));
//    NSNumber *timeStamp = [NSNumber numberWithUnsignedLong:7];
//    const uint8_t *tsBytes = [data bytes];
//    NSLog(@"%@", timeStamp);
    //    NSLog(@"received %@ from %@", DisplayStringFromData(data), DisplayAddressForAddress(addr));
}

- (void)echo:(UDP *)echo didReceiveError:(NSError *)error
// This UDP delegate method is called after a failure to receive data.
{
    assert(echo == self.echo);
#pragma unused(echo)
    assert(error != nil);
    //NSLog(@"received error: %@", DisplayErrorFromError(error));
}

- (void)echo:(UDP *)echo didSendData:(NSData *)data toAddress:(NSData *)addr
// This UDP delegate method is called after successfully sending data.
{
    assert(echo == self.echo);
#pragma unused(echo)
    assert(data != nil);
    assert(addr != nil);
    NSLog(@"    sent %@ to   %@", DisplayStringFromData(data), DisplayAddressForAddress(addr));
}

- (void)echo:(UDP *)echo didFailToSendData:(NSData *)data toAddress:(NSData *)addr error:(NSError *)error
// This UDP delegate method is called after a failure to send data.
{
    assert(echo == self.echo);
#pragma unused(echo)
    assert(data != nil);
    assert(addr != nil);
    assert(error != nil);
    NSLog(@" sending %@ to   %@, error: %@", DisplayStringFromData(data), DisplayAddressForAddress(addr), DisplayErrorFromError(error));
}

- (void)echo:(UDP *)echo didStartWithAddress:(NSData *)address;
// This UDP delegate method is called after the object has successfully started up.
{
    assert(echo == self.echo);
#pragma unused(echo)
    assert(address != nil);
    
    if (self.echo.isServer) {
        NSLog(@"receiving on %@", DisplayAddressForAddress(address));
    } else {
        NSLog(@"sending to %@", DisplayAddressForAddress(address));
    }
    
    //if ( ! self.echo.isServer ) {
    //    [self sendPacket];
        
        //assert(self.sendTimer == nil);
        //self.sendTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(sendPacket) userInfo:nil repeats:YES];
   // }
}

- (void)echo:(UDP *)echo didStopWithError:(NSError *)error
// This UDP delegate method is called  after the object stops spontaneously.
{
    assert(echo == self.echo);
#pragma unused(echo)
    assert(error != nil);
    NSLog(@"failed with error: %@", DisplayErrorFromError(error));
    self.echo = nil;
}


- (void) stop
{
    [self.echo stop];
}

- (void)dealloc
{
    [super dealloc];
}

@end
